package cn.stylefeng.guns.modular.ums.service.impl;

import cn.stylefeng.guns.base.auth.exception.AuthException;
import cn.stylefeng.guns.base.auth.exception.enums.AuthExceptionEnum;
import cn.stylefeng.guns.base.pojo.page.LayuiPageFactory;
import cn.stylefeng.guns.base.pojo.page.LayuiPageInfo;
import cn.stylefeng.guns.core.constants.RecommendType;
import cn.stylefeng.guns.core.constants.VipType;
import cn.stylefeng.guns.core.constants.exception.BusinessExceptionEnum;
import cn.stylefeng.guns.modular.cms.entity.AdPosition;
import cn.stylefeng.guns.modular.ums.entity.Member;
import cn.stylefeng.guns.modular.ums.entity.MemberAccount;
import cn.stylefeng.guns.modular.ums.entity.MemberRecommendRecords;
import cn.stylefeng.guns.modular.ums.mapper.MemberAccountMapper;
import cn.stylefeng.guns.modular.ums.mapper.MemberMapper;
import cn.stylefeng.guns.modular.ums.model.params.MemberAccountParam;
import cn.stylefeng.guns.modular.ums.model.params.MemberParam;
import cn.stylefeng.guns.modular.ums.model.params.MemberRecommendRecordsParam;
import cn.stylefeng.guns.modular.ums.model.params.RecommendIncomeRecordsParam;
import cn.stylefeng.guns.modular.ums.model.result.MemberResult;
import cn.stylefeng.guns.modular.ums.service.MemberAccountService;
import cn.stylefeng.guns.modular.ums.service.MemberRecommendRecordsService;
import  cn.stylefeng.guns.modular.ums.service.MemberService;
import cn.stylefeng.guns.modular.ums.service.RecommendIncomeRecordsService;
import cn.stylefeng.guns.sys.core.exception.enums.BizExceptionEnum;
import cn.stylefeng.guns.sys.core.util.SaltUtil;
import cn.stylefeng.guns.utils.DateUtils;
import cn.stylefeng.guns.utils.StringUtil;
import cn.stylefeng.guns.utils.json.JsonUtils;
import cn.stylefeng.roses.core.util.ToolUtil;
import cn.stylefeng.roses.kernel.model.exception.RequestEmptyException;
import cn.stylefeng.roses.kernel.model.exception.ServiceException;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * <p>
 * 会员信息表 服务实现类
 * </p>
 *
 */
@Service
public class MemberServiceImpl extends ServiceImpl<MemberMapper, Member> implements MemberService {

    @Resource
    private MemberAccountService memberAccountService;
    @Resource
    private MemberMapper memberMapper;
    @Resource
    private MemberRecommendRecordsService memberRecommendRecordsService;
    @Resource
    private RecommendIncomeRecordsService  recommendIncomeRecordsService;


    private static final BigDecimal extendMoney=new BigDecimal(20);
    private static final int recommendStuNumber=3;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Member add(MemberParam param){
        String code=param.getRemark();
        param.setRemark(null);
        //判定会员手机号是否存在
        Member member=new Member();
        member.setPhone(param.getPhone());
        MemberResult mb = this.baseMapper.getMember(param);
        if (mb != null) {
            throw new ServiceException(BusinessExceptionEnum.USER_ALREADY_REG);
        }
        Member new_member = getEntity(param);
        // 完善账号信息
        if (StringUtil.isNotEmpty(param.getPassword())){
            String salt = SaltUtil.getRandomSalt();
            String t_pass = SaltUtil.md5Encrypt(param.getPassword(), salt);
            new_member.setPassword(t_pass);
            new_member.setSalt(salt);
        }
        new_member.setName(param.getPhone());
        new_member.setMemberSn(StringUtil.getOutTradeNo());
        this.save(new_member);

        //创建会员账户信息
        MemberAccount account=new MemberAccount();
        account.setMemberId(new_member.getMemberId());
        memberAccountService.save(account);

        //根据邀请码查询上级用户
        if (!StringUtils.isEmpty(code)){
            Member member1=baseMapper.selectOne(new QueryWrapper<Member>().eq("code",code));
            if (member1!=null){
                //上级用户存在
//                member1.setRecommenderNumber(member1.getRecommenderNumber()+1);
//                this.updateById(member1);
                this.manageRecommendNumber(0,member1);
                //添加推广记录
                MemberRecommendRecordsParam recommendRecordsParam=new MemberRecommendRecordsParam();
                recommendRecordsParam.setTeacherId(member1.getMemberId());
                recommendRecordsParam.setMemberId(new_member.getMemberId());
                memberRecommendRecordsService.add(recommendRecordsParam);
                //更新上级ID
                new_member.setRecommendType(RecommendType.NormalMember.getValue());
                new_member.setRecommenderId(member1.getMemberId());
                this.baseMapper.updateById(new_member);
            }
        }
        return new_member;
    }

    @Override
    public void delete(MemberParam param){
//        this.removeById(getKey(param));
        //软删除，记录保存
        param.setIfDel(1);
        param.setDeleteTime(new Date());
        this.update(param);
    }

    /**
     * 修改会员信息
     * @param param
     */
    @Override
    @Transactional
    public boolean update(MemberParam param){
        Member oldEntity = getOldEntity(param);
        Member newEntity = getEntity(param);
        ToolUtil.copyProperties(newEntity, oldEntity);
        return this.updateById(newEntity);
    }

    @Transactional
    @Override
    public boolean memberValidation(MemberParam param) {
        Member oldEntity = getOldEntity(param);
        Member newEntity = getEntity(param);
        ToolUtil.copyProperties(newEntity, oldEntity);
        this.updateById(newEntity);
        Member member=this.getById(param.getMemberId());
        if (member.getRecommenderId() !=null){
            Member upMember=this.getById(member.getRecommenderId());
            //上级存在
            if (upMember!=null){
                //0-普通用户，1-学生，2-教师
//                if (param.getMemberRole()==1){
//                    upMember.setStudentNumber(upMember.getStudentNumber()+1);
//                }else if(param.getMemberRole()==2){
//                    upMember.setTeacherNumber(upMember.getTeacherNumber()+1);
//                }
//                this.updateById(upMember);
//                //判定推广数量判定，并进行奖励操作
//                this.promotionManage(upMember);

                if (param.getMemberRole()==1){
                    this.manageRecommendNumber(RecommendType.Student.getValue(),upMember);
                    param.setRecommendType(RecommendType.Student.getValue());
                }if (param.getMemberRole()==2){
                   this.manageRecommendNumber(RecommendType.Teacher.getValue(),upMember);
                   param.setRecommendType(RecommendType.Teacher.getValue());
                }
                param.setVerifyTime(new Date());
                this.update(param);
            }
        }
        return true;
    }

    @Override
    public boolean updateMemberVipExpire() {
        System.out.println("会员VIP到期处理");
        //查询VIP到期
        QueryWrapper queryWrapper=new QueryWrapper();
        //当前之前时间
        queryWrapper.le("vip_end_date",new Date());
        //当前VIP
        queryWrapper.ne("vip_grade",0);

        int count=memberMapper.selectCount(queryWrapper);
        System.out.println("到期会员数量："+count);

        //VIP等级取消
        Member entity=new Member();
        entity.setVipGrade(VipType.Default.getValue());
        memberMapper.update(entity,queryWrapper);
        return true;
    }

    /**
     * 更新会员VIP
     *
     * @param number 数量
     * @param  vipId 1-月度会员，2-季度会员，3-年度会员，4-终身会员
     * @author yzb
     * @Date 2019-11-07
     */
    @Override
    public boolean updateMemberVip(int number,int vipId, Integer memberId) {
        //则需要修改会员VIP状态
        MemberParam memberParam =new MemberParam();
        memberParam.setMemberId(memberId);
        //需要判断先前是否为VIP
        Member member=this.getById(memberId);
        Date endDate=null;//结束日期
        if (member.getVipGrade()>0){//非普通会员
            // 取等级高的
            if (member.getVipGrade().intValue() < vipId){
                memberParam.setVipGrade(vipId);
            }else{
                memberParam.setVipGrade(member.getVipGrade());
            }
            switch (vipId){
                case 1://月度会员
                    endDate= DateUtils.addDateDays(member.getVipEndDate(),30);
                    break;
                case 2://季度会员
                    endDate=DateUtils.addDateMonths(member.getVipEndDate(),3);
                    break;
                case 3://年度会员
                    endDate=DateUtils.addDateMonths(member.getVipEndDate(),12);
                    break;
                case 4://终身会员
                    endDate=DateUtils.addDateYears(member.getVipEndDate(),100);
                    break;
            }
            memberParam.setVipEndDate(endDate);
        }else{
            memberParam.setVipGrade(vipId);
            switch (vipId){
                case 1://月度会员
                    endDate=DateUtils.addDateDays(new Date(),30);
                    break;
                case 2://季度会员
                    endDate=DateUtils.addDateMonths(new Date(),3);
                    break;
                case 3://年度会员
                    endDate=DateUtils.addDateMonths(new Date(),12);
                    break;
                case 4://终身会员
                    endDate=DateUtils.addDateYears(new Date(),100);
                    break;
            }
            memberParam.setVipEndDate(endDate);
        }
        this.update(memberParam);
        return true;
    }

    @Transactional
    @Override
    public Member updateRecommendNumber(int type, Member param) {
        if (type==RecommendType.NormalMember.getValue()){
            param.setRecommenderNumber(param.getRecommenderNumber()+1);
        }else if (type ==RecommendType.Student.getValue()){//学生
            param.setStudentNumber(param.getStudentNumber()+1);
        }else if(type == RecommendType.Teacher.getValue()){//教师
            param.setTeacherNumber(param.getTeacherNumber()+1);
        }else if(type == RecommendType.BindedStudent.getValue()){//绑定学生
            param.setBindStudentNumber(param.getBindStudentNumber()+1);
        }else if(type == RecommendType.FinishTeacher.getValue()){//完成任务教师
            param.setBindTeacherNumber(param.getBindTeacherNumber()+1);
        }
        this.updateById(param);
        return param;
    }

    @Override
    public boolean manageRecommendNumber(int type, Member param) {
        Member member=this.updateRecommendNumber(type,param);
        //判定推广数量判定，并进行奖励操作
        if (member.getBindStudentNumber()==recommendStuNumber){//7个学生
            //此时判断该教师是否有上线。
            if (member.getRecommenderId()!=null && member.getRecommenderId() !=0){
                Member upmember=memberMapper.selectById(member.getRecommenderId());
                if (upmember!=null){
                    //更新上线教师的有效推广教师数量
                    Member member2= this.updateRecommendNumber(RecommendType.FinishTeacher.getValue(),upmember);
                    this.promotionManage(member2);
                    //更新自己完成状态和时间
                    member.setBinded(1);
                    member.setRecommendType(RecommendType.FinishTeacher.getValue());
                    member.setBindedTime(new Date());
                    this.memberMapper.updateById(member);
                }
            }
        }
        this.promotionManage(member);
        return true;
    }

    @Transactional
    @Override
    public boolean promotionManage(Member param) {
        //推广机制判定处理
//        类型0+7：推荐7个学生与自己绑定师生关系，奖励1个月VIP
//        类型1+7：推荐1个老师，7个学生（学生可重复），且推荐的老师完成类型0+7，即可获得2个月VIP
//        类型2+7：推荐2个老师，7个学生（学生可重复），且推荐的老师完成类型0+7,即可获得3个月VIP，100元消费券（仅用于指定资源消费）
//        类型3+7：推荐3个老师，7个学生（学生可重复），且推荐的老师完成类型0+7,即可获得4个月VIP，200元消费券（仅用于指定资源消费）
//        类型4+7：推荐4个老师，7个学生（学生可重复），且推荐的老师完成类型0+7,即可获得6个月VIP，300元消费券（仅用于指定资源消费）
//        类型5+7：推荐5个老师，7个学生（学生可重复），且推荐的老师完成类型0+7,即可获得一年VIP，500元消费券（仅用于指定资源消费）
//        所推荐的老师中完成了上面任何一个类型，完成一个奖励20消费券
        if (param.getBindStudentNumber()>=recommendStuNumber){//7个学生
            RecommendIncomeRecordsParam recommendIncomeRecordsParam=new RecommendIncomeRecordsParam();
            //推广会员信息
            switch (param.getBindTeacherNumber()){
                case 0://奖励一个月VIP
                        this.updateMemberVip(1, VipType.MonthVip.getValue(),param.getMemberId());
                        //添加收益记录
                        recommendIncomeRecordsParam.setIncomeType(1);
                        recommendIncomeRecordsParam.setIncome("1个月VIP");
                        recommendIncomeRecordsParam.setContent("推广7个已绑定自己的学生");
                        recommendIncomeRecordsParam.setMemberId(param.getMemberId());
                        recommendIncomeRecordsService.add(recommendIncomeRecordsParam);
                        //如果是被推广教师，则能额外获取奖励
                        if (param.getRecommenderId() !=null && param.getRecommenderId() != 0){
                            memberAccountService.addMemberBalance(extendMoney,param.getMemberId());
                            recommendIncomeRecordsParam.setIncomeType(0);
                            recommendIncomeRecordsParam.setIncome("20个消费券");
                            recommendIncomeRecordsParam.setContent("被推广教师完成推广0+7任务奖励");
                            recommendIncomeRecordsParam.setMemberId(param.getMemberId());
                            recommendIncomeRecordsService.add(recommendIncomeRecordsParam);
                        }
                    break;
                case 1://可获得2个月VIP
                    this.updateMemberVip(2, VipType.MonthVip.getValue(),param.getMemberId());
                    //添加收益记录
                    recommendIncomeRecordsParam.setIncomeType(1);
                    recommendIncomeRecordsParam.setIncome("2个月VIP");
                    recommendIncomeRecordsParam.setContent("推广7个已绑定自己的学生，加上1个完成0+7任务的教师");
                    recommendIncomeRecordsParam.setMemberId(param.getMemberId());
                    recommendIncomeRecordsService.add(recommendIncomeRecordsParam);
                    //如果是被推广教师，则能额外获取奖励
                    if (param.getRecommenderId() !=null && param.getRecommenderId() != 0){
                        memberAccountService.addMemberBalance(extendMoney,param.getMemberId());
                        recommendIncomeRecordsParam.setIncomeType(0);
                        recommendIncomeRecordsParam.setIncome("20个消费券");
                        recommendIncomeRecordsParam.setContent("被推广教师完成推广1+7任务奖励");
                        recommendIncomeRecordsParam.setMemberId(param.getMemberId());
                        recommendIncomeRecordsService.add(recommendIncomeRecordsParam);
                    }
                    break;
                case 2://可获得3个月VIP，100元消费券
                    this.updateMemberVip(3, VipType.MonthVip.getValue(),param.getMemberId());
                    //添加收益记录
                    recommendIncomeRecordsParam.setIncomeType(1);
                    recommendIncomeRecordsParam.setIncome("3个月VIP");
                    recommendIncomeRecordsParam.setContent("推广7个已绑定自己的学生，加上2个完成0+7任务的教师");
                    recommendIncomeRecordsParam.setMemberId(param.getMemberId());
                    recommendIncomeRecordsService.add(recommendIncomeRecordsParam);

                    memberAccountService.addMemberBalance(new BigDecimal(100),param.getMemberId());
                    recommendIncomeRecordsParam.setIncomeType(0);
                    recommendIncomeRecordsParam.setIncome("100个消费券");
                    recommendIncomeRecordsParam.setContent("推广7个已绑定自己的学生，加上2个完成0+7任务的教师");
                    recommendIncomeRecordsParam.setMemberId(param.getMemberId());
                    recommendIncomeRecordsService.add(recommendIncomeRecordsParam);
                    //如果是被推广教师，则能额外获取奖励
                    if (param.getRecommenderId() !=null && param.getRecommenderId() != 0){
                        memberAccountService.addMemberBalance(extendMoney,param.getMemberId());
                        recommendIncomeRecordsParam.setIncomeType(0);
                        recommendIncomeRecordsParam.setIncome("20个消费券");
                        recommendIncomeRecordsParam.setContent("被推广教师完成推广2+7任务奖励");
                        recommendIncomeRecordsParam.setMemberId(param.getMemberId());
                        recommendIncomeRecordsService.add(recommendIncomeRecordsParam);
                    }
                    break;
                case 3://可获得4个月VIP，200元消费券
                    this.updateMemberVip(4, VipType.MonthVip.getValue(),param.getMemberId());
                    //添加收益记录
                    recommendIncomeRecordsParam.setIncomeType(1);
                    recommendIncomeRecordsParam.setIncome("4个月VIP");
                    recommendIncomeRecordsParam.setContent("推广7个已绑定自己的学生，加上3个完成0+7任务的教师");
                    recommendIncomeRecordsParam.setMemberId(param.getMemberId());
                    recommendIncomeRecordsService.add(recommendIncomeRecordsParam);

                    memberAccountService.addMemberBalance(new BigDecimal(200),param.getMemberId());
                    recommendIncomeRecordsParam.setIncomeType(0);
                    recommendIncomeRecordsParam.setIncome("200个消费券");
                    recommendIncomeRecordsParam.setContent("推广7个已绑定自己的学生，加上3个完成0+7任务的教师");
                    recommendIncomeRecordsParam.setMemberId(param.getMemberId());
                    recommendIncomeRecordsService.add(recommendIncomeRecordsParam);

                    //如果是被推广教师，则能额外获取奖励
                    if (param.getRecommenderId() !=null && param.getRecommenderId() != 0){
                        memberAccountService.addMemberBalance(extendMoney,param.getMemberId());
                        recommendIncomeRecordsParam.setIncomeType(0);
                        recommendIncomeRecordsParam.setIncome("20个消费券");
                        recommendIncomeRecordsParam.setContent("被推广教师完成推广3+7任务奖励");
                        recommendIncomeRecordsParam.setMemberId(param.getMemberId());
                        recommendIncomeRecordsService.add(recommendIncomeRecordsParam);
                    }
                    break;
                case 4://获得6个月VIP，300元消费券
                    this.updateMemberVip(6, VipType.MonthVip.getValue(),param.getMemberId());
                    //添加收益记录
                    recommendIncomeRecordsParam.setIncomeType(1);
                    recommendIncomeRecordsParam.setIncome("6个月VIP");
                    recommendIncomeRecordsParam.setContent("推广7个已绑定自己的学生，加上4个完成0+7任务的教师");
                    recommendIncomeRecordsParam.setMemberId(param.getMemberId());
                    recommendIncomeRecordsService.add(recommendIncomeRecordsParam);

                    memberAccountService.addMemberBalance(new BigDecimal(300),param.getMemberId());
                    recommendIncomeRecordsParam.setIncomeType(0);
                    recommendIncomeRecordsParam.setIncome("300个消费券");
                    recommendIncomeRecordsParam.setContent("推广7个已绑定自己的学生，加上4个完成0+7任务的教师");
                    recommendIncomeRecordsParam.setMemberId(param.getMemberId());
                    recommendIncomeRecordsService.add(recommendIncomeRecordsParam);

                    //如果是被推广教师，则能额外获取奖励
                    if (param.getRecommenderId() !=null && param.getRecommenderId() != 0){
                        memberAccountService.addMemberBalance(extendMoney,param.getMemberId());
                        recommendIncomeRecordsParam.setIncomeType(0);
                        recommendIncomeRecordsParam.setIncome("20个消费券");
                        recommendIncomeRecordsParam.setContent("被推广教师完成推广4+7任务奖励");
                        recommendIncomeRecordsParam.setMemberId(param.getMemberId());
                        recommendIncomeRecordsService.add(recommendIncomeRecordsParam);
                    }
                    break;
                case 5://可获得一年VIP，500元消费券
                    this.updateMemberVip(1, VipType.YearVip.getValue(),param.getMemberId());
                    //添加收益记录
                    recommendIncomeRecordsParam.setIncomeType(1);
                    recommendIncomeRecordsParam.setIncome("1个年VIP");
                    recommendIncomeRecordsParam.setContent("推广7个已绑定自己的学生，加上5个完成0+7任务的教师");
                    recommendIncomeRecordsParam.setMemberId(param.getMemberId());
                    recommendIncomeRecordsService.add(recommendIncomeRecordsParam);

                    memberAccountService.addMemberBalance(new BigDecimal(500),param.getMemberId());
                    recommendIncomeRecordsParam.setIncomeType(0);
                    recommendIncomeRecordsParam.setIncome("500个消费券");
                    recommendIncomeRecordsParam.setContent("推广7个已绑定自己的学生，加上5个完成0+7任务的教师");
                    recommendIncomeRecordsParam.setMemberId(param.getMemberId());
                    recommendIncomeRecordsService.add(recommendIncomeRecordsParam);

                    //如果是被推广教师，则能额外获取奖励
                    if (param.getRecommenderId() !=null && param.getRecommenderId() != 0){
                        memberAccountService.addMemberBalance(extendMoney,param.getMemberId());
                        recommendIncomeRecordsParam.setIncomeType(0);
                        recommendIncomeRecordsParam.setIncome("20个消费券");
                        recommendIncomeRecordsParam.setContent("被推广教师完成推广5+7任务奖励");
                        recommendIncomeRecordsParam.setMemberId(param.getMemberId());
                        recommendIncomeRecordsService.add(recommendIncomeRecordsParam);
                    }
                    break;
            }
        }
        return true;
    }

    @Override
    public MemberResult findBySpec(MemberParam param){
        return null;
    }

    @Override
    public List<MemberResult> findListBySpec(MemberParam param){
        return memberMapper.customList(param);
    }

    @Override
    public LayuiPageInfo findPageBySpec(MemberParam param){
        Page pageContext = getPageContext();
        IPage page = this.baseMapper.customPageList(pageContext, param);
        return LayuiPageFactory.createPageInfo(page);
    }

    @Override
    public Page<Map<String, Object>> findPageMapBySpec(MemberParam param) {
        Page pageContext = getPageContext();
        return this.baseMapper.customPageMapList(pageContext,param);
    }

    /**
     * 取得会员信息
     * @param param 主要传输ID、手机号或者身份证等唯一性参数
     * @return
     */
    @Override
    public MemberResult getMember(MemberParam param) {

        return memberMapper.getMember(param);
    }


    /**
     * 会员登陆时时验证信息
     * @param phone  手机号
     * @param password  密码
     * @param verifyCode  验证码
     * @return
     */
    @Override
    public MemberResult getMemberForLogin(String phone,String password,String verifyCode) {

        MemberParam param = new MemberParam();
        param.setPhone(phone);
        MemberResult memberResult =  memberMapper.getMember(param);
        if (ToolUtil.isOneEmpty(memberResult)){
            //判断用户是否存在，如果不存在则自动注册
            MemberParam memberParam = new MemberParam();
            memberParam.setPhone(phone);
            memberParam.setPassword(password);
            memberParam.setCode(StringUtil.toSerialCode(this.count()));
            memberParam.setNickName(phone);
            Member curr_member = this.add(memberParam);
            memberResult=JsonUtils.fromJson(JsonUtils.toJsonStr(curr_member),MemberResult.class);
        }
        //验证参数是否为手机验证码
        if(verifyCode.equals("NO_CODE")){
            //验证账号密码是否正确
            String requestMd5 = SaltUtil.md5Encrypt(password, memberResult.getSalt());
            String dbMd5 = memberResult.getPassword();
            if (dbMd5 == null || !dbMd5.equalsIgnoreCase(requestMd5)) {
                throw new AuthException(AuthExceptionEnum.USERNAME_PWD_ERROR);
            }
        }
        return memberResult;
    }

    @Override
    public Member getMemberByPhone(String phone) {
        return baseMapper.selectOne(new QueryWrapper<Member>().eq("phone",phone));
    }

    @Override
    public MemberResult getMemberByOpenId(String openId) {
        return baseMapper.getMember(new MemberParam().setOpenId(openId));
    }

    private Serializable getKey(MemberParam param){
        return param.getMemberId();
    }

    private Page getPageContext() {
        return LayuiPageFactory.defaultPage();
    }

    private Member getOldEntity(MemberParam param) {
        return this.getById(getKey(param));
    }

    private Member getEntity(MemberParam param) {
        Member entity = new Member();
        ToolUtil.copyProperties(param, entity);
        return entity;
    }

}
